﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.DirectoryServices;
using System.Collections;


using groupAnalyzer.Observers;

namespace groupAnalyzer.connectivity
{
    class LdapConnectivity
    {
        private string host;
        private string baseDN;
        private string username;
        private string password;
        private Observer errorObserver;

        private List<string> AttributeValuesMultiString(string attributeName,string objectDn)
        {
            List<string> valuesCollection = new List<string>();
            DirectoryEntry ent = new DirectoryEntry(objectDn);
            PropertyValueCollection ValueCollection = ent.Properties[attributeName];
            IEnumerator en = ValueCollection.GetEnumerator();

            while (en.MoveNext())
            {
                if (en.Current != null)
                {
                    if (!valuesCollection.Contains(en.Current.ToString()))
                    {
                        valuesCollection.Add(en.Current.ToString());
                        
                    }
                }
            }
            ent.Close();
            ent.Dispose();
            return valuesCollection;
        }

        private List<DirectoryEntry> getEntries(string searchFilter)
        {
            List<DirectoryEntry> entries = new List<DirectoryEntry>();
            string distinguishedName = string.Empty;
            string connectionPrefix = "LDAP://" + this.host + "/" + this.baseDN;
            DirectoryEntry entry = new DirectoryEntry(connectionPrefix,this.username, this.password);
            DirectorySearcher mySearcher = new DirectorySearcher(entry);
            
            mySearcher.Filter = searchFilter;
            SearchResultCollection results = null;
            // critical 
            try
            {
                results = mySearcher.FindAll();
            }
            catch (Exception e)
            {
                this.errorObserver.notifiy(Messages.error, e.Message);
                return new List<DirectoryEntry>();
            }
            foreach (SearchResult result in results)
            {
                entries.Add(result.GetDirectoryEntry());
            }
            return entries;
        }

        public List<DirectoryEntry> getElementsOfLevel(string fqdnPath)
        {
            List<DirectoryEntry> elementsOfLevel = new List<DirectoryEntry>();
            string domainADsPath = string.Empty;
            DirectoryEntry ParentEntry = new DirectoryEntry(domainADsPath);
            try
            {
                foreach (DirectoryEntry childEntry in ParentEntry.Children)
                {
/*                    TreeNode Node = new TreeNode(childEntry.Name);

                    switch (childEntry.SchemaClassName.ToString())
                    {
                        case "organizationalUnit":
                            TreeNode ParentDomain = new TreeNode(childEntry.Name.Substring(childEntry.Name.Length - 2));
                            TreeNode[] range = { ParentDomain };
                            treeView.Nodes.AddRange(range);
                            ParentDomain.Tag = childEntry.Path;
                            break;

                    }*/
                }

            }
            catch (System.Exception error)
            {
                // ho dont know
                throw error;

            }
            finally
            {
                ParentEntry = null;
            }
            return elementsOfLevel;

        }

        public string getProperty(DirectoryEntry entry, string propertyName, int index)
        {
            string propertyValue = "";
            Object tmp = entry.Properties[propertyName];
            if (entry.Properties[propertyName].Value != null)
            {
                return entry.Properties[propertyName][index].ToString();
            }
            return propertyValue;
        }

        public List<DirectoryEntry> getUsersOfGroup(string fqdnGroup)
        {
            List<DirectoryEntry> usersOfGroup = this.getEntries("(&(objectClass=person)(memberOf=" + fqdnGroup + "))");

            return usersOfGroup;
        }

        public List<DirectoryEntry> getAllAnalyzable()
        {
            List<DirectoryEntry> analyzeable = this.getEntries("(&(objectClass=person)(!(memberOf=\"\")))");
            return analyzeable;
        }

        public List<DirectoryEntry> getAllUsers()
        {
            List<DirectoryEntry> users = this.getEntries("(&(objectClass=organizationalPerson)(objectClass=person)(objectClass=top)(objectClass=user))");
            return users;
        }

        public List<DirectoryEntry> getAllGroups()
        {
            List<DirectoryEntry> entries = this.getEntries("(objectClass=group)");
            return entries;
        }

        public Dictionary<string,DirectoryEntry> getAllGroupsHashmap()
        {
            Dictionary<string, DirectoryEntry> groups = new Dictionary<string, DirectoryEntry>();
            List<DirectoryEntry> entries = this.getAllGroups();
            // wandle in hashmap um
            foreach (DirectoryEntry entry in entries)
            {
                groups.Add(entry.Properties["distinguishedName"][0].ToString(), entry);
            }
            return groups;
        }

        public List<DirectoryEntry> searchGroup(string groupName)
        {
            List<DirectoryEntry> matchingGroups = this.getEntries("(&(objectClass=group)(name=*" + groupName + "*))");

            return matchingGroups;
        }

        private LdapConnectivity(string ldapDomain, string baseDn, string username, string password, Observer errorObserver)
        {
            this.host = ldapDomain;
            this.baseDN = baseDn;
            this.username = username;
            this.password = password;
            this.errorObserver = errorObserver;
        }

        public static LdapConnectivity constructLdapConnectivity()
        {
            LdapConnectivity connectivity = new LdapConnectivity("192.168.56.5", "dc=test,dc=home", "Administrator@test.home", "p4ssw0rd!", Observer.getGlobalObserver());
            return connectivity;
        }
    }
    
}
